package com.logica.mdm.webservices.dao.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.logica.mdm.webservices.dao.CrmAccountDao;
import com.logica.mdm.webservices.dataobject.crm.account.AccountData;
import com.logica.mdm.webservices.dataobject.crm.account.AddressData;
import com.logica.mdm.webservices.dataobject.crm.account.ContactData;
import com.logica.mdm.webservices.dataobject.mdm.CLuAddressTypeConstants;
import com.logica.mdm.webservices.dataobject.mdm.CLuPartyRelTypeConstants;
import com.logica.mdm.webservices.dataobject.mdm.CleansePutTypedResponse;
import com.logica.mdm.webservices.messages.CleansePutCrmAccountCompositeRequest;
import com.logica.mdm.webservices.utils.SiperianRequestUtils;
import com.siperian.sif.client.SiperianClient;
import com.siperian.sif.message.SiperianRequest;
import com.siperian.sif.message.mrm.CleansePutResponse;
import com.siperian.sif.message.nexity.mappings.CleansePutCrmAddressRelRequest;
import com.siperian.sif.message.nexity.mappings.CleansePutCrmPartyRelRequest;
//import com.siperian.sif.message.nexity.mappings.CleansePutCrmPhoneFaxAccountRequest;

/**
 * CrmAccountDao implementation backed by Informatica MDM Hub SiperianClient.
 * Note that due to SiperianClient not being thread-safe, this class is not thread-safe either.
 * @author Fabien Crespel <fabien.crespel@logica.com>
 */
public class SiperianClientCrmAccountDao implements CrmAccountDao {

	private static final Logger logger = LoggerFactory.getLogger(SiperianClientCrmAccountDao.class);
	
	protected SiperianClient siperianClient;

	/**
	 * Constructor taking an existing SiperianClient instance.
	 * @param siperianClient
	 */
	public SiperianClientCrmAccountDao(SiperianClient siperianClient) {
		this.siperianClient = siperianClient;
	}
	
	@Override
	public List<CleansePutTypedResponse> cleansePutCrmAccount(CleansePutCrmAccountCompositeRequest crmAccountCompositeRequest) throws Exception {
		AccountData account = crmAccountCompositeRequest.getAccount();
		
		// Init the requests/responses lists
		List<SiperianRequest> requests = new ArrayList<SiperianRequest>();
		List<CleansePutTypedResponse> responses = new ArrayList<CleansePutTypedResponse>();
		
		// Check account type and perform specific actions
		if (CLuPartyRelTypeConstants.TYPE_SOCIETE.equals(account.getAccountType()) ||
			CLuPartyRelTypeConstants.TYPE_COPROPRIETE.equals(account.getAccountType()) ||
			CLuPartyRelTypeConstants.TYPE_INDIVISION.equals(account.getAccountType()) ||
			CLuPartyRelTypeConstants.TYPE_COLOCATION.equals(account.getAccountType()) ||
			CLuPartyRelTypeConstants.TYPE_COUPLE.equals(account.getAccountType())) {
			// In case of TYPE_SOCIETE, TYPE_COPROPRIETE, TYPE_INDIVISION, TYPE_COLOCATION or TYPE_COUPLE, we create the account, its addresses and link its contacts
			
			// Account
			requests.add(SiperianRequestUtils.buildCleansePutRequest("CrmAccount", crmAccountCompositeRequest, account));			
			requests.add(SiperianRequestUtils.buildCleansePutRequest("CrmAccountDetails", crmAccountCompositeRequest, account));
			requests.add(SiperianRequestUtils.buildCleansePutRequest("CrmPhoneDomAccount", crmAccountCompositeRequest, account));
			requests.add(SiperianRequestUtils.buildCleansePutRequest("CrmPhoneFaxAccount", crmAccountCompositeRequest, account));
			requests.add(SiperianRequestUtils.buildCleansePutRequest("CrmUrlAccount", crmAccountCompositeRequest, account));
			
			// Address
			if (account.getListOfAddress() != null) {
				for (AddressData address : account.getListOfAddress().getAddress()) {
					// CleansePutCrmAddress
					requests.add(SiperianRequestUtils.buildCleansePutRequest("CrmAddress", crmAccountCompositeRequest, address));
					
					// CleansePutCrmAddressRel
					CleansePutCrmAddressRelRequest request = (CleansePutCrmAddressRelRequest) SiperianRequestUtils.buildCleansePutRequest("CrmAddressRel", crmAccountCompositeRequest, account);
					request.getCrmAddressRelInput().setPartyId(account.getId());
					request.getCrmAddressRelInput().setAddressId(address.getId());
					if (address.getId().equals(account.getPrimaryBillToAddressId())) {
						// Primary
						request.getCrmAddressRelInput().setAddressType(CLuAddressTypeConstants.TYPE_PERSO_PRINCIPALE);
					} else {
						// Secondary
						request.getCrmAddressRelInput().setAddressType(CLuAddressTypeConstants.TYPE_PERSO_SECONDAIRE);
					}
					requests.add(request);
				}
			}
			
			// Party Rel
			if (account.getListOfContact() != null) {
				for (ContactData contact : account.getListOfContact().getContact()) {
					CleansePutCrmPartyRelRequest request = (CleansePutCrmPartyRelRequest) SiperianRequestUtils.buildCleansePutRequest("CrmPartyRel", crmAccountCompositeRequest, account);
					request.getCrmPartyRelInput().setPartyId1(account.getId());
					request.getCrmPartyRelInput().setPartyId2(contact.getContactId());
					request.getCrmPartyRelInput().setRelType(account.getAccountType());
					request.getCrmPartyRelInput().setIdAccountOcod(account.getId());
					requests.add(request);
				}
			}
			
		} else if (CLuPartyRelTypeConstants.TYPE_PERSONNE_PHYSIQUE.equals(account.getAccountType())) {
			// In case of TYPE_PERSONNE_PHYSIQUE, we only link the primary contact to itself
			if (StringUtils.isNotBlank(account.getPrimaryContactId())) {
				CleansePutCrmPartyRelRequest request = (CleansePutCrmPartyRelRequest) SiperianRequestUtils.buildCleansePutRequest("CrmPartyRel", crmAccountCompositeRequest, account);
				request.getCrmPartyRelInput().setPartyId1(account.getPrimaryContactId());
				request.getCrmPartyRelInput().setPartyId2(account.getPrimaryContactId());
				request.getCrmPartyRelInput().setRelType(account.getAccountType());
				request.getCrmPartyRelInput().setIdAccountOcod(account.getId());
				requests.add(request);
			}
			
		}
		
		// Perform the requests
		logger.info("START processing of " + requests.size() + " requests...");
		for (SiperianRequest request : requests) {
			logger.info("Processing '" + request.getClass().getSimpleName() + "'...");
			CleansePutResponse response = (CleansePutResponse) siperianClient.process(request);
			responses.add(new CleansePutTypedResponse(response));
		}
		logger.info("END processing of " + requests.size() + " requests.");
		
		return responses;
	}

}
